class Loom < ActiveRecord::Base
  
  belongs_to  :loom_state
  belongs_to  :fabric
  belongs_to  :roll
  
  belongs_to  :doffer,  
              :class_name => "User", 
              :foreign_key => :doffer_id
  
  belongs_to  :weft_container, 
              :class_name => "Container", 
              :foreign_key => "weft_container_id"
              
  belongs_to  :warp_container, 
              :class_name => "Container", 
              :foreign_key => "warp_container_id"
              
  belongs_to  :creel_container, 
              :class_name => "Container", 
              :foreign_key => "creel_container_id"
              
  has_many    :loom_loads
  
  def after_initialize
    # set class variables for loom states
    @idle     = LoomState.find_by_code(0)
    @loaded   = LoomState.find_by_code(1)
    @weaving  = LoomState.find_by_code(2)
    
    # set class variables for container states
    @inventory  = ContainerState.find_by_code(0)
    @production = ContainerState.find_by_code(1)
    @consumed   = ContainerState.find_by_code(2)
    
    # set class variables for roll states
    @roll_created = RollState.find_by_code(0)
    @roll_weaving = RollState.find_by_code(1)
    @roll_woven   = RollState.find_by_code(2)
    
    # set variables to contain the appropirate load types
    @warp  = LoadType.find_by_code(0)
    @weft  = LoadType.find_by_code(1)
    @creel = LoadType.find_by_code(2)
  end
  
  def before_create
    self.loom_state = @idle
  end
  
  # a few methods that describe the state of the looms
  def is_idle
    self.loom_state == @idle
  end
  
  def is_weaving
    self.loom_state == @weaving
  end
  
  def is_loaded
    loaded = false
    warp = false
    weft = false
    creel = false
    
    if fabric != nil
      # Test each container against the appropriate yarn
      # indicated in the fabric style definition to ensure
      # that the right type of yarn is loaded in to the loom
      # for the farbic to be produced.
      
      if warp_container.nil? 
        warp = true unless !fabric.warp_yarn.nil?
      elsif warp_container.yarn == fabric.warp_yarn
        warp = true
      end
      
      if weft_container.nil?
        weft = true unless !fabric.weft_yarn.nil?
      elsif weft_container.yarn == fabric.weft_yarn
        weft = true
      end
      
      if creel_container.nil?
        warp = true unless !fabric.creel_yarn.nil?
      elsif creel_container.yarn == fabric.creel_yarn
        creel = true
      end
    end
    # all three values should reflect the fabric defintion
    # only then is the loom 'loaded'
    if warp && weft && creel
      loaded = true
    end
    # return the result
    loaded
  end
  
  # This method starts the loom 'weaving' a roll of fabric.
  # It will create a new roll and add the containers currently
  # loaded on the loom to it. Then it will set the state of the
  # loom to 'weaving.'

  def start
    started = false
    if is_loaded && !fabric.nil?
      # Create a new roll if one does not exist
      if roll.nil?
        self.roll = Roll.new
        self.roll.doffer = self.doffer
        self.roll.fabric = self.fabric
        self.roll.roll_state  = @roll_created
        started = self.roll.save!
      end
      
      add_load(self.warp_container, @warp)
      add_load(self.weft_container, @weft)
      add_load(self.creel_container, @creel)
      
      self.roll.roll_state = @roll_weaving # don't know if I need this.
      self.roll.save!
      
      self.loom_state = @weaving
      started = true
    end
    started
  end
  
  # This just sets the roll state to woven and the loom state to idle
  # thereby completing the 'weaving' of a roll.
  
  def complete_weaving
    result = false
    self.roll.roll_state = @roll_woven
    if self.roll.save
      result = true
    end
    self.roll = nil
    doffer = nil
    self.loom_state = @idle
    result
  end
  
  # load_container loads a container of yarn onto a given spindle by type.
  # The loaded container is removed from inventory and it's state set to 
  # 'production'. If there is a load already on the loom it will be set to 
  # 'consumed' meaning that ALL the yarn in a container has been used in the 
  # production of rolls of fabric. Once a container is 'consumed' it can no
  # longer be added back to the inventory.
  
  def load_container(container, type)
    result = false
    
    # First clear the existing container.
    if clear_container(type.code)
      case type.code
      when @warp.code
        self.warp_container = container
      when @weft.code
        self.weft_container = container
      when @creel.code
        self.creel_container = container
      end
      # set the state the container to production, meaning that 
      # it has been romoved from inventory and in the weaving 
      # process.
      container.container_state = @production
      result = container.save
    end
    if result and self.is_weaving
      result = add_load(container,type)
    end
    result
  end
  
  # unload_container removes a container of yarn from a loom and adds
  # it back to inventory.
  
  def unload_container(type)
    result = false
    
    # set the appropriate the container by type code
    case type
    when 0
      self.warp_container.container_state = @inventory
      if self.warp_container.save
        self.warp_container = nil
        result = true
      end
    when 1
      self.weft_container.container_state = @inventory
      if self.weft_container.save
        self.weft_container = nil
        result = true
      end
    when 2
      self.creel_container.container_state = @inventory
      if self.creel_container.save
        self.creel_container = nil
        result = true
      end
    end
    result
  end
  
  # clear_container sets a containers status to 'consumed' and 
  # removes it from the loom (sets it to nil).
  
  def clear_container(type)
    result = false
    case type
    when 0
      if self.warp_container
        # clear load if exists
        self.warp_container.container_state = @consumed
        if self.warp_container.save
          result = true
          self.warp_container = nil
        end
      else
        result = true
      end
    when 1
      if self.weft_container
        # clear load if exists 
        self.weft_container.container_state = @consumed
        if self.weft_container.save
          result = true
          self.weft_container = nil
        end
      else
        result = true
      end
    when 2
      if self.creel_container
        # clear load if exists and not same as the new value
        self.creel_container.container_state = @consumed
        if self.creel_container.save
          result = true
          self.creel_container = nil
        end
      else
        result = true
      end
    end
    result
  end
  
  def add_load(container, type) 
    # Add the load to the loom history and to the roll of fabric.
    load = LoomLoad.new
    load.load_type = type
    load.roll = self.roll
    load.loaded_at = Time.now
    load.loaded_by =  self.doffer
    load.container = container
    self.loom_loads.push(load)
  end
end
